#include "stdafx.h"
#include "InterestingClass.h"

using namespace com;
using namespace guysherman;
using namespace simulclass;
using namespace testhelpers;

InterestingClass::InterestingClass( MonoDomain* domain, MonoImage* image )
{
	// Hold onto the domain and image we were just given
	this->domain = domain;
	this->image = image;

	// Grab the class info
	this->me = mono_class_from_name( image, "com.guysherman.simulclass.testhelpers", "InterestingClass" );
	//! @TODO put in some error checking here to make sure we actually found the class

	// Get the fields
	this->valField = mono_class_get_field_from_name( this->me, "valField" );
	this->stringField = mono_class_get_field_from_name( this->me, "stringField" );
	this->refField = mono_class_get_field_from_name( this->me, "refField" );


	// Get the methods
	this->GetValFieldMonoMethod = mono_class_get_method_from_name( this->me, "GetValField", 0 );
	this->GetStringFieldMonoMethod = mono_class_get_method_from_name( this->me, "GetStringField", 0 );
	this->GetRefFieldMonoMethod = mono_class_get_method_from_name( this->me, "GetRefField", 0 );
	this->SetValFieldMonoMethod = mono_class_get_method_from_name( this->me, "SetValField", 1 );
	this->SetStringFieldMonoMethod = mono_class_get_method_from_name( this->me, "SetStringField", 1 );
	this->SetRefFieldMonoMethod = mono_class_get_method_from_name( this->me, "SetRefField", 1 );
	this->GetAllMonoMethod = mono_class_get_method_from_name( this->me, "GetAll", 3 );
	this->ToStringMonoMethod = mono_class_get_method_from_name( this->me, "ToString", 0 );
	this->EqualsMonoMethod = mono_class_get_method_from_name( this->me, "Equals", 1 );
	this->GetHashCodeMonoMethod = mono_class_get_method_from_name( this->me, "GetHashCode", 0 );
	this->GetTypeMonoMethod = mono_class_get_method_from_name( this->me, "GetType", 0 );
	this->FinalizeMonoMethod = mono_class_get_method_from_name( this->me, "Finalize", 0 );
	this->MemberwiseCloneMonoMethod = mono_class_get_method_from_name( this->me, "MemberwiseClone", 0 );

}

InterestingClass::~InterestingClass( void )
{

}

MonoObject* InterestingClass::_ctor(void)
{
	// Allocate
	MonoObject* result = mono_object_new( this->domain, this->me );

	// Init
	mono_runtime_object_init( result );

	return result;
}

int InterestingClass::_private_get_valField( MonoObject* target )
{
	// Declare where we want the result to go
	int value;

	// Get the value
	mono_field_get_value( target, this->valField, &value );

	// Return it
	return value;
}

void InterestingClass::_private_set_valField( MonoObject* target, int value )
{
	// Set the value
	mono_field_set_value( target, this->valField, &value );
}


LPTSTR InterestingClass::_internal_get_stringField( MonoObject* target )
{
	// Declare where we want the result to go
	MonoString* value;
	LPTSTR result;

	// Get the value
	mono_field_get_value( target, this->stringField, &value );
	result = (LPTSTR)mono_string_to_utf16( value );

	// Return it
	return result;
}

void InterestingClass::_internal_set_stringField( MonoObject* target, LPTSTR value )
{
	// Box the c_str into a MonoString
	MonoString* val = mono_string_new_utf16( this->domain, ( const mono_unichar2* )value, _tcslen( value ) );

	// Set the value
	mono_field_set_value( target, this->stringField, val );
}


MonoObject* InterestingClass::get_refField( MonoObject* target )
{
	// Declare where we want the result to go
	MonoObject* value;
	
	// Get the value
	mono_field_get_value( target, this->refField, &value );
	
	// Return it
	return value;
}

void InterestingClass::set_refField( MonoObject* target, MonoObject* value )
{
	// Set the value
	mono_field_set_value( target, this->refField, value );
}


int InterestingClass::GetValField(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->GetValFieldMonoMethod, target, args, NULL );

	int result = *(int*)mono_object_unbox(returnValue);
	return result;
}


LPTSTR InterestingClass::GetStringField(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->GetStringFieldMonoMethod, target, args, NULL );

	MonoString* result = ( MonoString* )returnValue;
	LPTSTR strResult = (LPTSTR)mono_string_to_utf16( result );
	return strResult;
}


MonoObject* InterestingClass::GetRefField(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->GetRefFieldMonoMethod, target, args, NULL );

	return returnValue;
}


void InterestingClass::SetValField(MonoObject* target, int value)
{
	void* args[1];

	args[0] = &value;


	MonoObject* returnValue = mono_runtime_invoke( this->SetValFieldMonoMethod, target, args, NULL );

}


void InterestingClass::SetStringField(MonoObject* target, LPTSTR valueString)
{
	void* args[1];

	MonoString* valueStringString = mono_string_new_utf16( this->domain, ( const mono_unichar2* )valueString, _tcslen( valueString ) );
	args[0] = valueStringString;


	MonoObject* returnValue = mono_runtime_invoke( this->SetStringFieldMonoMethod, target, args, NULL );

}


void InterestingClass::SetRefField(MonoObject* target, MonoObject* valueRef)
{
	void* args[1];

	args[0] = valueRef;


	MonoObject* returnValue = mono_runtime_invoke( this->SetRefFieldMonoMethod, target, args, NULL );

}


void InterestingClass::GetAll(MonoObject* target, int* val, LPTSTR* str, MonoObject** ec)
{
	void* args[3];

	args[0] = val;
	MonoString* strString = mono_string_new_utf16( this->domain, ( const mono_unichar2* )(*str), _tcslen( *str ) );
	args[1] = &strString;
	args[2] = ec;


	MonoObject* returnValue = mono_runtime_invoke( this->GetAllMonoMethod, target, args, NULL );
	(*str) = (LPTSTR)mono_string_to_utf16( strString );


}


LPTSTR InterestingClass::ToString(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->ToStringMonoMethod, target, args, NULL );

	MonoString* result = ( MonoString* )returnValue;
	LPTSTR strResult = (LPTSTR)mono_string_to_utf16( result );
	return strResult;
}


bool InterestingClass::Equals(MonoObject* target, MonoObject* obj)
{
	void* args[1];

	args[0] = obj;


	MonoObject* returnValue = mono_runtime_invoke( this->EqualsMonoMethod, target, args, NULL );

	bool result = *(bool*)mono_object_unbox(returnValue);
	return result;
}


int InterestingClass::GetHashCode(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->GetHashCodeMonoMethod, target, args, NULL );

	int result = *(int*)mono_object_unbox(returnValue);
	return result;
}


MonoObject* InterestingClass::GetType(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->GetTypeMonoMethod, target, args, NULL );

	return returnValue;
}


void InterestingClass::_protected_Finalize(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->FinalizeMonoMethod, target, args, NULL );

}


MonoObject* InterestingClass::_protected_MemberwiseClone(MonoObject* target)
{
	void** args = NULL;


	MonoObject* returnValue = mono_runtime_invoke( this->MemberwiseCloneMonoMethod, target, args, NULL );

	return returnValue;
}



